/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools resize load nat
 */

#include "load_nat.h"

#include <clocale>
#include <cstdbool>
#include <ctime>

#include "device_manager.h"
#include "hmfs_common.h"
#include "node.h"
#include "resize_load.h"

namespace OHOS {
namespace Hmfs {
LoadNat::LoadNat(ResizeLoad *loadPtr) : load_(loadPtr)
{
    config_ = load_->GetConfig();
    superBlockInfo_ = load_->GetSuperBlockInfo();
}

int32_t LoadNat::InitNidBitmapBegin()
{
    NodeAddressTable *nat = superBlockInfo_->nodeAddrTable;
    int nidBitmapSize = (nat->maxNodeId + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
    CurrentSegmentInfo *currentSegment = static_cast<CurrentSegmentInfo *>(
        superBlockInfo_->segmentTable->currentSegmentArray + CURSEG_DATA_HOT);
    SummaryBlockData *sum = currentSegment->summaryBlockData;
    JournalEntry *journal = &sum->journal;

    nat->nodeIdBitmap = static_cast<uint8_t *>(calloc(nidBitmapSize, 1));
    if (!nat->nodeIdBitmap) {
        return -ENOMEM;
    }
    HmfsCommon::GetInstance().SetBit(0, nat->nodeIdBitmap);
    uint16_t natCount = LE16ToNative(journal->natCount);
    if (natCount > NAT_JOURNAL_ENTRY_COUNT) {
        HMFS_ERROR("hmfs_init_nid_bitmap truncate natCount(%u) to NAT_JOURNAL_ENTRY_COUNT(%zu)",
            natCount, NAT_JOURNAL_ENTRY_COUNT);
        journal->natCount = NativeToLE16(NAT_JOURNAL_ENTRY_COUNT);
        config_->fixOn = 1;
    }

    for (int32_t i = 0; i < natCount; i++) {
        uint32_t addr = LE32ToNative(journal->natJournalArray.entries[i].natEntry.blockId);
        if (!IsValidBlkAddr(superBlockInfo_, addr)) {
            HMFS_ERROR("hmfs_init_nid_bitmap: addr(%u) is invalid!!!", addr);
            journal->natCount = NativeToLE16(i);
            config_->fixOn = 1;
            continue;
        }

        uint32_t nodeId = LE32ToNative(journal->natJournalArray.entries[i].nodeId);
        if (!IsValidNid(superBlockInfo_, nodeId)) {
            HMFS_ERROR("hmfs_init_nid_bitmap: nodeId(%u) is invalid!!!", nodeId);
            journal->natCount = NativeToLE16(i);
            config_->fixOn = 1;
            continue;
        }
        if (addr != NULL_ADDR) {
            HmfsCommon::GetInstance().SetBit(nodeId, nat->nodeIdBitmap);
        }
    }
    return SUCCESS_CODE;
}

int32_t LoadNat::InitNodeManager()
{
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    CheckPointData *checkPointData = superBlockInfo_->checkPointData;
    NodeAddressTable *nat = superBlockInfo_->nodeAddrTable;
    nat->natBlockddr = GetLeValue(superBlockData->natBlockId);
    uint32_t natSegs = GetLeValue(superBlockData->segmentCountInNAT) >> 1;
    nat->natBlocks = natSegs << GetLeValue(superBlockData->logBlksPerSeg);
    nat->maxNodeId = NAT_ENTRY_PER_BLOCK * nat->natBlocks;
    nat->fileCount = 0;
    nat->natCount = 0;
    nat->initScanNodeId = GetLeValue(checkPointData->nextFreeNodeId);
    nat->nextScanNodeId = GetLeValue(checkPointData->nextFreeNodeId);

    nat->bitmapSize = GetBitmapSize(superBlockInfo_, static_cast<int32_t>(BitmapType::NAT_BITMAP));

    nat->natBitmap = static_cast<uint8_t *>(malloc(nat->bitmapSize));
    if (nat->natBitmap == nullptr) {
        return -ENOMEM;
    }
    unsigned char *versionBitmap = reinterpret_cast<unsigned char *>(
        load_->GetBitmapPtr(static_cast<uint32_t>(BitmapType::NAT_BITMAP)));
    if (versionBitmap == nullptr) {
        return -EFAULT;
    }
    int ret = memcpy_s(nat->natBitmap, nat->bitmapSize, versionBitmap, nat->bitmapSize);
    HMFS_CHECK_ONLY_LOG(ret == 0, "Failed to copy version bitmap");
    return InitNidBitmapBegin();
}

int32_t LoadNat::BuildNodeManager()
{
    HMFS_DEBUG("Enter BuildNodeManager");
    superBlockInfo_->nodeAddrTable = static_cast<NodeAddressTable *>(malloc(sizeof(NodeAddressTable)));
    if (superBlockInfo_->nodeAddrTable == nullptr) {
        return -ENOMEM;
    }
    int32_t err = InitNodeManager();
    if (err != SUCCESS_CODE) {
        return err;
    }
    return SUCCESS_CODE;
}

int32_t LoadNat::HmfsLateInitNidBitmap()
{
    HMFS_DEBUG("Enter HmfsLateInitNidBitmap");
    NodeAddressTable *nat = superBlockInfo_->nodeAddrTable;
    uint32_t startBlk;
    if (!(config_->func == CmdFunc::SLOAD || config_->func == CmdFunc::FSCK)) {
        return SUCCESS_CODE;
    }
    NatBlockData *natBlock = static_cast<NatBlockData *>(malloc(HMFS_BLOCK_SIZE));
    HMFS_ASSERT(natBlock);
    load_->HmfsRaMetaPages(0, NatBlockOffset(nat->maxNodeId), static_cast<int32_t>(MetaType::META_NAT));
    for (uint32_t nodeId = 0; nodeId < nat->maxNodeId; nodeId++) {
        if (!(nodeId % NAT_ENTRY_PER_BLOCK)) {
            startBlk = CurrentNatAddr(superBlockInfo_, nodeId);
            int32_t ret = HmfsIo::GetInstance().DevReadBlock(natBlock, startBlk);
            HMFS_ASSERT_FREE(ret >= 0, natBlock);
        }
        if (natBlock->entries[nodeId % NAT_ENTRY_PER_BLOCK].blockId) {
            HmfsCommon::GetInstance().SetBit(nodeId, nat->nodeIdBitmap);
        }
    }
    free(natBlock);
    return SUCCESS_CODE;
}
} // namespace Hmfs
} // namespace OHOS